package gamecontrol;

import gameinfo.*;
import gameobjects.*;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.util.Vector;

/**
 * Controls the running of the game. Keeps the objects that participate in it,
 * and has the methods to access to them, modificate, control methods, etc... .
 * @author quique
 */
public class Game {
        
        /**
         * The name of the user. 
         */
	private String userName;
	
        /**
         * The board that in this moment controls.
         */
	private CurrentBoard currentBoard;
	
        /**
         * The current level that the player is.
         */
	private int currentLevel;
	
        /**
         * The remaining lives that the player has.
         */
	private int currentLifes;
	
        /**
         * The score that the player has.
         */
	private int currentScore;
	
        /**
         * Information about the setup of the differents level of the game.
         */
	private CollectionOfLevels levelsInfo;
	
        /**
         * The top scores of the game.
         */
	private TopScores topScores;
        
        /**
         * Indicates to control game method that the player advance into a new level
         */
	private boolean advancedToNextLevel;
        
        /**
         * Main method that controls the game.
         * @param args
         */
	public void main(){
            boolean exit = false;
            do{
                //initialize the game
                try {
                    startUp();
                }
                catch(Exception e){
                    System.out.println("Error in the start up. Type: "+e);
                }
                //start the game
                try{
                    startGame();
                }
                catch(Exception e){

                }
                //ask about play again
                try{
                    String s;
                    System.out.println("Do you want to play again? (yes/no): ");
                    BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
                    s = keyboard.readLine();
                    if(s.compareTo("no")==0)
                        exit=true;
                }
                catch(Exception e){
                    System.out.println("Error in the exit. Type: "+e);
                }
                updateTopScoresInMemory();
            }
            while(!exit);
            
            //write the scores into the file
            writeTopScoresToFile(topScores);
	}
	
        /**
         * 
         * @return user name
         */
	public String getUserName() {
		return userName;
	}
	
        /**
         * Ask the nick name to the user name.
         * @param userName
         */
	public String askUserName() throws IOException {
            String s;
            System.out.print("Introduce Your nick name: ");
            BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
            s = keyboard.readLine();
            return s;
	}
        
        /**
         * 
         * @return
         */
        public CollectionOfLevels getLevelsInfo(){
            return this.levelsInfo;
        }
	
        /**
         * 
         * @return the actual level of the game
         */
	public int getCurrentLevel() {
		return currentLevel;
	}
	
        /**
         * Loads the next level configuration.
         * @see #currentLevel
         * @see #getCurrentLevel()
         */
	public void advanceToNextLevel() {
            this.currentBoard.timer.stop();
            currentLevel = currentLevel+1;
            advancedToNextLevel = true;
	}
	
        /**
         * 
         * @return current lifes of the player
         */
	public int getCurrentLifes() {
		return currentLifes;
	}
	
        /**
         * Add a life to the currentLifes when the player catch a life.
         */
	public void addALife() {
            currentLifes = currentLifes+1;
	}
	
        /**
         * 
         * @return the current score that user has.
         */
	public int getCurrentScore() {
		return currentScore;
	}
	
        /**
         * Increases to the current score with the same value that the parameter.
         * @param increasing
         */
	public void increaseCurrentScore(int increasing) {
            this.currentScore = this.currentScore+increasing;
	}
	
        /**
         * Remove a life from the user's current lives 
         */
	public void subtractALife() {
            this.currentLifes=this.currentLifes-1;
            this.advancedToNextLevel = true;
            System.out.println("You lost a life, life remaining: "+currentLifes);
            System.out.println("Press any key to continue");
	}
	
        /**
         * Initializes the game loading info from files.
         */
        public void  startUp() throws FileNotFoundException, IOException{
            //inicialize to the first level
            this.currentLevel = 1;
            
            //inicialize the lifes to 5
            this.currentLifes = 5;
            
            //inicialize the score to 0
            this.currentScore = 0;
            
            //load level's info
            this.levelsInfo = readLevelsFromFile();
            
            //load the former top scores
            this.topScores = readTopScoresFromFile();
            
            //ask the nick to the user
            this.userName = askUserName();
            
            //initilize advancedToNextLevel
            this.advancedToNextLevel = true;
	}
	
        /**
         * Reads from a file the information of the configuration of all the levels.
         * @return the collection that keeps the Levels.
         */
	public CollectionOfLevels readLevelsFromFile()  throws FileNotFoundException, IOException{
            String s;
            String curDir = System.getProperty("java.class.path");
            curDir = curDir.substring(0, curDir.indexOf(":"));
            System.out.println(curDir);
            //open the file
            BufferedReader file = new BufferedReader(new FileReader(curDir+"/levels.txt"));
            
            //how many levels has the game
            int nrOfLevels;
            s = file.readLine();
            s = s.substring(s.indexOf(":")+1);
            nrOfLevels = Integer.parseInt(s);
            
            //create the CollectionOfLevels
            CollectionOfLevels collectionOfLevels = new CollectionOfLevels(nrOfLevels);
            
            //analize the levels
            for(int i=0;i<nrOfLevels;i++){
                Level level = new Level();
                
                //read number of the level
                s = file.readLine();
                s = s.substring(s.indexOf(":")+1);
                level.setNumberOfLevel(Integer.parseInt(s));
                
                //read dimension of the board
                s = file.readLine();
                s = s.substring(s.indexOf(":")+1);
                level.setXDimension(Integer.parseInt(s.substring(0,s.indexOf("x"))));
                level.setYDimension(Integer.parseInt(s.substring(s.indexOf("x")+1)));
                
                //read time
                s = file.readLine();
                s = s.substring(s.indexOf(":")+1);
                level.setInitialTime(Integer.parseInt(s));
                
                //read the intial help
                s = file.readLine();
                s = s.substring(s.indexOf(":")+1);
                level.setInitialHelp(s);
                
                //read all objects of the board
                //create the vector that cointains this info with the exactly size
                Vector vector = new Vector(level.getXDimension()*level.getYDimension());
                for(int j=0;j<level.getXDimension();j++){
                    for(int k=0;k<level.getYDimension();k++){
                        s = file.readLine();
                        s = s.substring(s.indexOf(":")+1);
                        vector.add(s);
                    }
                }
                level.setInitialBoard(vector);
                collectionOfLevels.addLevel(level, i+1);
            }
            return collectionOfLevels;
	}
	
        /**
         * Reads from a file the information of the top scores of the game.
         * @return the collection that keeps the TopScores.
         */
	public TopScores readTopScoresFromFile() throws FileNotFoundException, IOException{
            String s;
            String curDir = System.getProperty("java.class.path");
            curDir = curDir.substring(0, curDir.indexOf(":"));
            System.out.println(curDir);
            //open the file
            BufferedReader file = new BufferedReader(new FileReader(curDir+"/topScores.txt"));
            
            //create the TopScores collection
            TopScores topScores = new TopScores();
            int i = 1;

            //read all the scores until no more there is
            s = file.readLine();
            while(s != null){
                Score score = new Score();
                score.setScore(Integer.parseInt(s.substring(s.indexOf(":")+1)));
                score.setName(s.substring(0,s.indexOf(":")));
                s = file.readLine();
                topScores.addScore(score, i);
                i = i+1;
            }
            
            return topScores;
	}
	
        /**
         * Write into the corresponding file.
         * @param topScores
         * @return true if the writting is ok, false otherwise.
         */
	public boolean writeTopScoresToFile(TopScores topScores) {
            try{
                String s;
                String curDir = System.getProperty("java.class.path");
                curDir = curDir.substring(0, curDir.indexOf(":"));
                System.out.println(curDir);
                //open the file
                PrintStream file = new PrintStream(new File(curDir+"/topScores.txt"));
                //write the new data
                int i=1;
                while((i<6)&&(topScores.getScore(i)!=null)){
                    file.println(topScores.getScore(i).getName()+":"+topScores.getScore(i).getScore());
                    i++;
                }
                file.close();
                return true;
            }
            catch(Exception e){
                return false;
            }
	}
	
        /**
         * When a game is over, the top scores must be studied for possible updates. This method does it.
         * @return true if changes happened, false if not
         */
	public boolean updateTopScoresInMemory() {
            return topScores.updateTopScores(userName, currentScore);
	}
	
        /**
         * Configures the board of the number in the parameter, and sets the currentBoard
         * with its configuration.
         * @param numberOfLevel
         * @see #currentBoard
         */
	public void loadBoard(int numberOfLevel) {
            //aqui es donde pasa de vector (letras) a las clases correspondientes
            //asignar primero el currentBoard al juego y despues el juego a curren board
	}
	
        /**
         * Starts the game in the specified and loaded level.
         */
	
        public void startGame() throws IOException {
           
            do{ 
                if(advancedToNextLevel){
                    //load the the level if the user pass the last level
                    currentBoard = new CurrentBoard(this, levelsInfo.getLevel(currentLevel));
                    System.out.println("The game is going to start\nPress any key to continue");
                    if(this.readStringFromKeyboard()!=null){
                        currentBoard.startClock();
                    }
                    advancedToNextLevel = false;
                }
                
                //translate the keyboard user input in a hero movement
                int heroMovement = (int)this.readCharFromKeyboard();
                switch(heroMovement){
                    case('w'):
                        heroMovement = Hero.up;
                        break;
                    case('W'):
                        heroMovement = Hero.up;
                        break;
                    case('s'):
                        heroMovement = Hero.down;
                        break;
                    case('S'):
                        heroMovement = Hero.down;
                        break;
                    case('a'):
                        heroMovement = Hero.left;
                        break;
                    case('A'):
                        heroMovement = Hero.left;
                        break;
                    case('d'):
                        heroMovement = Hero.right;
                        break;
                    case('D'):
                        heroMovement = Hero.right;
                        break;
                }
                //first move of the hero
                currentBoard.getHero().move(heroMovement);
                
            }while((currentLevel<6)&&(currentLifes>0));
            if(currentLifes==0)
                System.out.println("GAME OVER");
            else
                System.out.println("GAME PASSED");
	}
	
        /**
         * Detects the string that user presses in the keyboard.
         * @return reading string
         */
	public String readStringFromKeyboard() throws IOException {
            BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
            String s = keyboard.readLine();
            return s;
	}
	
        /**
         * Detects the char that user presses in the keyboard.
         * @return reading char
         */
	public char readCharFromKeyboard() throws IOException {
            BufferedReader keyboard = new BufferedReader(new InputStreamReader(System.in));
            return (char)keyboard.read();
	}

        /**
         * Temporal method that draw the current board
         */
        public void drawBoard() {
            System.out.println("Level: "+this.getCurrentLevel()+" Score: "+this.getCurrentScore()+" Lifes: "+this.getCurrentLifes());
            for(int k=levelsInfo.getLevel(currentLevel).getYDimension();k>0;k--){
                for(int j=1;j<=levelsInfo.getLevel(currentLevel).getXDimension();j++){
                    System.out.print(currentBoard.getBoxes().getBox(j, k).getElement().getId());
                }
                System.out.println();
            }
            System.out.println("Remaining time: "+this.currentBoard.getRemainingTime());
        }
	 
}
 
